package com.hsy.swu.version

import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import androidx.core.content.FileProvider
import com.hsy.swu.hsyutils.MLog
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import java.io.File
import java.io.FileOutputStream
import java.io.IOException

class DownloadService : Service() {
    private var progressCallbackCounts = 0
    private var downloadProgressListener: ((Int) -> Unit)? = null

    inner class DownloadBinder : Binder() {
        fun getService() = this@DownloadService
    }

    fun setDownloadProgressListener(listener: (Int) -> Unit) {
        downloadProgressListener = listener
    }

    override fun onBind(intent: Intent?): IBinder {
        download(
            intent?.getFloatExtra("downloadSize", 0f) ?: 0f,
            intent?.getStringExtra("downloadUrl") ?: "",
            intent?.getStringExtra("storageFileName") ?: "",
            {
                downloadProgressListener?.invoke(100)
                if (it) {
                    installApk(intent?.getStringExtra("storageFileName") ?: "")
                } else {
                    downloadProgressListener?.invoke(-1)
                }
            }
        ) {
            // 由于下载进度回调的太快了，导致 Handler 处理不过来，导致显示的进度比实际进度慢很多；普通一次下载中，Handler 居然发了 3万多条 Message
            // 因此这里考虑发送消息时加限制，比如每 500 次回调才发送一次 Message
            if (progressCallbackCounts++ % 500 == 0) {
                downloadProgressListener?.invoke((it * 100).toInt())
            }
        }
        return DownloadBinder()
    }

    private fun download(
        downloadSize: Float,
        downloadUrl: String,
        storageFileName: String,
        resultCallback: (Boolean) -> Unit,
        progressCallback: (Float) -> Unit
    ) {
        val apkByteSize = downloadSize * 1024 * 1024
        val client = OkHttpClient()
        val request = Request.Builder()
            .url(downloadUrl)
            .header(
                "User-Agent",
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
            )
            .build()
        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                resultCallback(false)
            }

            override fun onResponse(call: Call, response: Response) {
                if (response.body == null) {
                    resultCallback(false)
                    return
                }
                MLog.attention(System.currentTimeMillis().toString())
                val mIS = response.body!!.byteStream()
                var mOS: FileOutputStream? = null

                try {
                    mOS = FileOutputStream(storageFileName)
                    val buffer = ByteArray(1024)
                    var readCount: Int
                    var totalReadCount: Long = 0
                    var progress: Float
                    while (mIS.read(buffer).also { readCount = it } != -1) {
                        mOS.write(buffer, 0, readCount)
                        totalReadCount += readCount.toLong()
                        progress = totalReadCount / apkByteSize
                        progressCallback(progress)
                    }
                    mOS.flush()
                    resultCallback(true)
                } catch (e: Exception) {
                    MLog.attention(e.toString())
                    resultCallback(false)
                } finally {
                    mIS.close()
                    mOS?.close()
                }
                MLog.attention(System.currentTimeMillis().toString())
            }
        })
    }

    private fun installApk(storageFileName: String) {
        val apkUri = FileProvider.getUriForFile(
            applicationContext,
            "${applicationContext.packageName}.fileprovider",
            File(storageFileName)
        )
        val intent = Intent("android.intent.action.VIEW")
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        intent.setDataAndType(apkUri, "application/vnd.android.package-archive")
        startActivity(intent)
    }
}